/*
 * @Author: wangshuixin 2412658453@qq.com
 * @Date: 2025-05-17 23:40:30
 * @LastEditors: wangshuixin 2412658453@qq.com
 * @LastEditTime: 2025-06-19 19:27:43
 * @FilePath: /my-app/src/utils/wordExporter.ts
 * @Description:  Word文档导出器（提供创建和导出Word文档的功能）
 */
import { ref, type Ref } from 'vue'
import { Document, Paragraph, TextRun, HeadingLevel, Table, TableRow, TableCell, Packer, AlignmentType } from "docx"
import type { IParagraphOptions, IRunOptions, TabStopDefinition, IIndentAttributesProperties, ITableBordersOptions, TableLayoutType, ISpacingProperties, PositiveUniversalMeasure, HeightRule, TableVerticalAlign } from 'docx'

type HexColor = `#${string}` | string

// 定义段落文本样式选项
interface ParagraphOptions extends IParagraphOptions {
  bold?: boolean; // 是否加粗
  italics?: boolean; // 是否斜体
  underline?: boolean | string | { type?: string; color?: string }; // 根据 docx 类型定义
  color?: HexColor;  // 十六进制颜色代码，如 "FF0000"
  font?: string; // 字体
  fontSize?: number; // 字号（单位：磅，如 12 表示 12pt）
  headFontSize?: number; // 表头字号
  spacing?: ISpacingProperties; // 行间距
  headSpacing?: ISpacingProperties; // 表头行间距
  height?: {
    value: number | PositiveUniversalMeasure;
    rule: (typeof HeightRule)[keyof typeof HeightRule];
  }; // 行高
  headHeight?: {
    value: number | PositiveUniversalMeasure;
    rule: (typeof HeightRule)[keyof typeof HeightRule];
  }; // 表头行高
  spacingBefore?: number; // 段前间距
  spacingAfter?: number; // 段后间距 >>> 单位：缇（twip），1 twip = 1/20磅（约 1/1440英寸）
  alignment?: (typeof AlignmentType)[keyof typeof AlignmentType]; // 对齐方式
  headVerticalAlign?: TableVerticalAlign; // 表头垂直对齐方式
  headAlignment?: (typeof AlignmentType)[keyof typeof AlignmentType]; // 表头水平对齐方式
  wordWrap?: boolean, // 是否允许文本自动换行
  indent?: IIndentAttributesProperties, // 首行缩进
  border?: ITableBordersOptions, // 边框样式
  headerWidth?: number; // “表头垂直”表格的表头宽度
  columnWidths?: number[]; // 列宽配置
  columnCount?: number; // 所有行的列数最大值
  layout?: (typeof TableLayoutType)[keyof typeof TableLayoutType]; // 自动调整的模式
}

export type TextRunObjectType = { text: string, style?: ParagraphOptions }
// 表格单元格内容类型
type WordTableCell = TextRunObjectType[][]; // 二维数组，支持多段落
// 表格列
interface WordTableColumn {
  data: WordTableCell;
  [property: string]: any;
}
// 表格行
type WordTableRow = WordTableColumn[];

// 默认的表格边框样式
const defaultTableBorder = (options?: ParagraphOptions | undefined): ITableBordersOptions | undefined => {
  // docx 库中 size 的单位是 1/8 磅（即 size: 8 = 1 磅，size: 6 = 0.75 磅）。
  return {
    top: { style: options?.border?.top?.style || "single", size: options?.border?.top?.size || 12, color: options?.border?.top?.color || "000000" },
    bottom: { style: options?.border?.bottom?.style || "single", size: options?.border?.bottom?.size || 12, color: options?.border?.bottom?.color || "000000" },
    left: { style: options?.border?.left?.style || "single", size: options?.border?.left?.size || 12, color: options?.border?.left?.color || "000000" },
    right: { style: options?.border?.right?.style || "single", size: options?.border?.right?.size || 12, color: options?.border?.right?.color || "000000" },
    insideHorizontal: { style: options?.border?.insideHorizontal?.style || "single", size: options?.border?.insideHorizontal?.size || 6, color: options?.border?.insideHorizontal?.color || "000000" }, // 内部水平线保持细线
    insideVertical: { style: options?.border?.insideVertical?.style || "single", size: options?.border?.insideVertical?.size || 6, color: options?.border?.insideVertical?.color || "000000" }    // 内部垂直线保持细线
  }
}

// 厘米转换dxa单位
export const cmToDxa = (cm: number) => Math.round(cm * 567); // 1厘米 ≈ 567 dxa
/**
 * 将磅（pt）转换为缇（dxa/twips）
 * @param pt 磅值
 * @returns 对应的缇值
 */
export const ptToDxa = (pt: number): number => Math.round(pt * 20);

export class WordExporter {
  private children: Ref<any[]> = ref([]); // 使用 Ref 包装
  constructor() {
    this.children.value = [];
  }
  
  /**
   * 添加标题
   * @param lines 接受字符串数组，每个元素代表一行/段
   * @param options 标题、段落内容的样式和布局
   * @param level 值对应 Word 的标题级别（通常为 1~6）；level=1 → 一级标题（HeadingLevel.HEADING_1）、level=2 → 二级标题（HeadingLevel.HEADING_2）
   * 
  */
  addTitle(lines: string[], options: ParagraphOptions = {}, level?: number): this {
    // 默认字体回退链：优先尝试小标宋体，失败后依次尝试宋体、黑体
    const defaultFontFallback = "小标宋体, SimSun, SimHei, Microsoft YaHei, sans-serif";
    
    lines.forEach((line, index) => {
      const isLastLine = index === lines.length - 1;
      this.children.value.push(
        new Paragraph({
          children: [
            new TextRun({
              text: line,
              bold: options.bold ?? false, // 标题默认加粗
              font: options.font ?? defaultFontFallback, // 优先用选项传入的字体，默认小标宋体
              size: options.fontSize ? options.fontSize * 2 : 44, // 二号字对应24磅（Word中二号字≈24pt），44半磅=22磅二号字
              color: isValidColor(options.color) ? options.color : "000000",
            })
          ],
          heading: HeadingLevel[`HEADING_${level}`],
          alignment: options.alignment || AlignmentType.CENTER, // 默认居中
          spacing: options?.spacing ?? {
            before: options.spacingBefore ?? 0, // 清除段前间距
            after: isLastLine ? (options.spacingAfter ?? 0) : 0 // 段后间距
          },
          indent: options.indent, // 首行缩进,如：1cm（约567dxa）
          wordWrap: options.wordWrap ?? true, // 允许文本自动换行
        })
      );
    });
    
    return this;
  }

  /**
   * 添加段落
  */
  addParagraph(paragraphData: TextRunObjectType[], options: ParagraphOptions = {}): this {
    const paragraph = new Paragraph({
      alignment: options?.alignment ?? "left",
      children: paragraphData?.map((item: TextRunObjectType) => {
        return new TextRun({
          ...item?.style as Omit<IRunOptions, 'text' | 'size'>,
          text: item?.text.replace(/\n/g, '\\n'), // 保留换行符，docx库会自动处理
          size: item?.style?.fontSize ? item?.style.fontSize * 2 : (item?.style?.size ? item?.style?.size as number * 2 : 22), // 默认16磅 = 32 half-points（半磅）
        })
      }),
      indent: options?.indent ? options?.indent : { firstLine: cmToDxa(0) },
      tabStops: options?.tabStops ? options?.tabStops.map((t: TabStopDefinition) => ({
        position: t.position ?? cmToDxa(2),
        type: t.type ?? "left",
      }))  : [{
        position: cmToDxa(2), // 制表位位置（单位：twips）
        type: "left",
      }],
      spacing: {
        line: options?.spacing?.line ?? 320, // 行距320twips（≈16pt）
        lineRule: options?.spacing?.lineRule ?? "exact",
        before: options?.spacing?.before ?? 0, // 清除段前间距
        after: options?.spacing?.after ?? 0, // 段后间距
      },
      wordWrap: options?.wordWrap ?? true, // 允许文本自动换行
    });
    this.children.value.push(paragraph);
    return this;
  }
  
  /**
   * 新增表格
  */
  addTableCell(colRowData: any): TableCell {
    return new TableCell({
      verticalAlign: colRowData?.verticalAlign ?? "left",
      columnSpan: colRowData?.columnSpan ?? 1,
      rowSpan: colRowData?.rowSpan ?? 1,
      width: {
        size: colRowData?.width?.size ?? 100, // // 宽度值（百分比或固定单位）
        type: colRowData?.width?.type ?? 'pct', // 单位类型：百分比 ("pct") 或 固定值 ("dxa")
      },
      children: colRowData?.data.map(textGroup => {
        return new Paragraph({
          alignment: colRowData?.alignment ?? "left",
          children: textGroup.map(item => {
            return new TextRun({
              ...item?.style,
              text: item.text.replace(/\n/g, '\\n'), // 保留换行符，docx库会自动处理
              size: item?.style?.fontSize ? item?.style.fontSize * 2 : (item?.style.size ? item?.style.size * 2 : 22), // 默认16磅 = 32 half-points（半磅）
            });
          }),
          indent: colRowData?.indent ? colRowData?.indent : { firstLine: cmToDxa(0) },
          tabStops: colRowData?.tabStops ? colRowData?.tabStops.map(t => ({
            position: t.position ?? cmToDxa(2),
            type: t.type ?? "left",
          }))  : [{
            position: cmToDxa(2), // 制表位位置（单位：twips）
            type: "left",
          }],
          spacing: {
            line: colRowData?.spacing?.line ?? 320, // 行距320twips（≈16pt）
            lineRule: colRowData?.spacing?.lineRule ?? "exact",
            before: colRowData?.spacing?.before ?? 0, // 清除段前间距
            after: colRowData?.spacing?.after ?? 0, // 段后间距
          },
          wordWrap: colRowData?.wordWrap ?? true, // 允许文本自动换行
        });
      }),
      shading: { 
        fill: colRowData?.backgroundColor ?? "FFFFFF" // 单元格背景色
      }
    });
  }

  /**
   * 新增表格行
  */
  addTableRow(rowData: [], options?: ParagraphOptions): TableRow {
    return new TableRow({
      height: options?.height ? options?.height : { value: 560, rule: "auto" }, // 行高560twips（≈28pt）
      children: rowData.map(colRowData => this.addTableCell(colRowData)),
    });
  }

  /**
   * 添加表格到文档
  */
  addTable(contents: [], options?: ParagraphOptions): this {
    const tableRows: TableRow[] = contents.map(rowData => {
      return this.addTableRow(rowData, options)
    })
    
    // 步骤1：定义一个虚拟的"最大列数"（取所有行的列数最大值）
    const MAX_COLUMNS = options?.columnCount ?? 1; // 例如：第一行2列，第二行3列 → 取6（最小公倍数）

    // 4. 创建表格
    const table = new Table({
      rows: tableRows,
      width: { size: 100, type: "pct" }, // 自动撑满可用空间 >>> size: 100：宽度值为 100。type: "pct"：单位是百分比（pct = percent）。
      columnWidths: options?.columnCount ? Array(MAX_COLUMNS).fill(100/MAX_COLUMNS) : options?.columnWidths, // 定义表格每一列的宽度，均分列宽 （单位：dxa，1/20 磅，约 1/1440 英寸），1厘米 ≈ 567 dxa。
      borders: defaultTableBorder(options),
      indent: { size: cmToDxa(5) },
      layout: options?.layout ?? "autofit" // 禁止任何自动调整
    });
    this.children.value.push(table);
    return this;
  }

  addPageBreak() {
    this.children.value.push(new Paragraph({ text: "", pageBreakBefore: true }));
    return this;
  }
  
  async generate(): Promise<Uint8Array | Blob> {
    const doc = new Document({ 
      sections: [{
        properties: {
          page: {
            margin: {
              left: cmToDxa(2.1),   // 默认约 1 inch (1440 twips)，这里设为 0.5 inch
              right: cmToDxa(2.1),  // 同上
              top: cmToDxa(1.8),   // 上边距保持默认 1 inch
              bottom: cmToDxa(1.55), // 下边距保持默认
            },
          },
        },
        children: this.children.value
      }],
    });
    // #ifdef H5
      // H5 环境：返回 Blob
      return await Packer.toBlob(doc);
    // #endif

    // #ifdef MP-WEIXIN
      // 微信小程序环境：返回 Uint8Array
      const arrayBuffer = await Packer.toArrayBuffer(doc);
      return new Uint8Array(arrayBuffer);
    // #endif
  }
}

// 使用时可以添加验证函数
function isValidColor(color: string | undefined): color is HexColor {
  return color ? (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color) || /^[A-Fa-f0-9]{6}$/.test(color)) : false;
}